#include "Pajarito.h"
#include "ActoresConstantes.h"
#include "UtilidadesConstantes.h"

using namespace TP::Juego::Arena::Actores;

double Pajarito::_calcularNuevaVelocidad() {
	/*-1*(sqrt(10*2*this->getAlturaRebote()*_altura_maxima_salto_actual))*/
	_altura_maxima_salto_actual =
			getAlturaRebote() * _altura_maxima_salto_actual;
	return -1 * _altura_maxima_salto_actual;
}

Pajarito::Pajarito() : Actor("", new Rol(PAJARITO, DESC_ACTOR)) {
	setEsEnemigo(true);
	_altura_maxima_salto_actual = 60;
}

Pajarito::Pajarito(const string& pNombre) : Actor(pNombre,
		new Rol(pNombre, DESC_ACTOR)) {
	setEsEnemigo(true);
	_altura_maxima_salto_actual = 60;
}

Pajarito::~Pajarito() { }

IColisionado* Pajarito::colisionar(IColisionado* pColisionado) {
	// Si colisiono contra el piso.
	if (pColisionado->getRol()->Descripcion() == DESC_PISO) {
		return (IColisionado*)colisionarContraPiso((Piso*)pColisionado);
	} // Si colisiono contra el perímetro.
	else if (pColisionado->getRol()->Descripcion() == DESC_PERIMETRO) {
		return (IColisionado*)colisionarContraPerimetro(
				(Perimetro*)pColisionado);
	} // Si colisiono contra una utilidad.
	else if (pColisionado->getRol()->Descripcion() == DESC_UTILIDAD) {
		return (IColisionado*)colisionarContraUtilidad((Utilidad*)pColisionado);
	} // Si colisiono contra un actor.
	else if (pColisionado->getRol()->Descripcion() == DESC_ACTOR) {
		return (IColisionado*)colisionarContraActor((Actor*)pColisionado);
	}
	return pColisionado;
}

string Pajarito::aXML() {
	TiXmlDocument* doc = new TiXmlDocument();
	TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", "");
	doc->LinkEndChild(decl);

	doc->LinkEndChild(this->aElementoXML());

	TiXmlPrinter printer;
	doc->Accept(&printer);
	return printer.CStr();
}

string Pajarito::aXML(const string& pPath) {
	TiXmlDocument* doc = new TiXmlDocument(pPath.c_str());
	TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", "");
	doc->LinkEndChild(decl);

	doc->LinkEndChild(this->aElementoXML());

	TiXmlPrinter printer;
	doc->Accept(&printer);
	return printer.CStr();
}

void Pajarito::parseXML(const string& pDescriptor) {
	TiXmlDocument doc;
	doc.Parse(pDescriptor.c_str(), 0, TIXML_ENCODING_UTF8);
	this->deElementoXML(doc.FirstChildElement());
}

Actor* Pajarito::colisionarContraActor(Actor* pActor) {
	long int dx = pow(this->getTrayectoria()->getPosicion()->X() - 
		pActor->getTrayectoria()->getPosicion()->X(), 2);
	long int dy = pow(this->getTrayectoria()->getPosicion()->Y() -
		pActor->getTrayectoria()->getPosicion()->Y(), 2);
	long int dr = sqrt(dx + dy);
	long int sumRadio = this->getRadio() + pActor->getRadio();

	if ((dr < sumRadio) && (this->esEnemigo() != pActor->esEnemigo()))
		this->decrementarEnergia(pActor->getDanioContraPajarito());
	return pActor;
}

Utilidad* Pajarito::colisionarContraUtilidad(Utilidad* pUtilidad) {
	long int dx = pow(this->getTrayectoria()->getPosicion()->X() - 
		pUtilidad->getPosicion()->X(), 2);
	long int dy = pow(this->getTrayectoria()->getPosicion()->Y() - 
		pUtilidad->getPosicion()->Y(), 2);
	long int dr = sqrt(dx + dy);
	long int sumRadio = this->getRadio() + pUtilidad->getRadio();

	 // Si la distancia entre los centros es < a la suma de los radios -> choque
	if ((dr < sumRadio)) {
		pUtilidad->decrementarEnergia(this->getDanioContraSuperficie());
		this->destruir();
	}
	return pUtilidad;
}

Perimetro* Pajarito::colisionarContraPerimetro(Perimetro* pPerimetro) {
	if ((this->getTrayectoria()->getPosicion()->X() - this->getRadio() < 0) ||
			(this->getTrayectoria()->getPosicion()->X() +
				this->getRadio() > pPerimetro->getAncho()) ||
			(this->getTrayectoria()->getPosicion()->Y() -
				this->getRadio() < 0) ||
			(this->getTrayectoria()->getPosicion()->Y() +
				this->getRadio() > pPerimetro->getAlto()))
		this->destruir();
	return pPerimetro;
}

Piso* Pajarito::colisionarContraPiso(Piso* pPiso) {
	vector<Posicion*> posiciones = pPiso->getVectorPosiciones();
	double pendiente, puntoDePaso, distancia_punto_recta;
	double xPajaro = this->getTrayectoria()->getPosicion()->X();
	double yPajaro = this->getTrayectoria()->getPosicion()->Y();
	double nuevaVelocidadY;
	Trayectoria* nuevaTrayectoria;
	Posicion *nuevaPosicion;
	Vector2D *nuevaVelocidad, *nuevaAceleracion;

	if (!posiciones.empty()) {
		// Si hay puntos de piso -> recorro todos esos puntos.
		for (size_t i = 0; i < posiciones.size() - 1; ++i) {
			// Saco la pendiente y el punto de paso que une 2 puntos contiguos.
			this->_obtenerAtributosDeRecta(posiciones[i], posiciones[i + 1],
					pendiente, puntoDePaso);
			// Saco la distancia del centro del pájaro a la recta.
			distancia_punto_recta = abs(pendiente * xPajaro - yPajaro +
					puntoDePaso) / sqrt(pow(pendiente, 2) + 1);
			// Me fijo si esa distancia es menor que el radio.
			if (this->getRadio() > distancia_punto_recta) {

				//hago el rebote 
				// Le saco un poco de vida al pájaro por rebotar contra el piso
				this->decrementarEnergia(danio_piso_pajaro); 
				if (!this->destruido()) { // Si no lo maté, lo hago rebotar.
					nuevaVelocidadY = _calcularNuevaVelocidad();
					nuevaVelocidad = new Vector2D(this->getTrayectoria(
							)->getVelocidad()->X(), nuevaVelocidadY);
					nuevaPosicion = new Posicion(this->getTrayectoria(
							)->getPosicion()->X(), this->getTrayectoria(
							)->getPosicion()->Y());
					nuevaAceleracion = new Vector2D(this->getTrayectoria(
							)->getAceleracion()->X(), this->getTrayectoria(
							)->getAceleracion()->Y());
					nuevaTrayectoria = new Trayectoria(nuevaPosicion,
							nuevaVelocidad, nuevaAceleracion);
					this->setTrayectoria(nuevaTrayectoria);
				}
			}
		}
	}
	return pPiso;
}